/*******************************************************************************
 * Copyright (c) 2007 University of Oslo.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     University of Oslo - initial API and implementation
 *******************************************************************************/

package com.cea.papyrus.diagram.sequence.sedi.edit;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartFactory;
import org.eclipse.uml2.uml.CombinedFragment;
import org.eclipse.uml2.uml.Comment;
import org.eclipse.uml2.uml.Constraint;
import org.eclipse.uml2.uml.Continuation;
import org.eclipse.uml2.uml.DestructionEvent;
import org.eclipse.uml2.uml.DurationObservation;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Event;
import org.eclipse.uml2.uml.ExecutionSpecification;
import org.eclipse.uml2.uml.Interaction;
import org.eclipse.uml2.uml.InteractionConstraint;
import org.eclipse.uml2.uml.InteractionOperand;
import org.eclipse.uml2.uml.InteractionUse;
import org.eclipse.uml2.uml.Lifeline;
import org.eclipse.uml2.uml.Message;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.OccurrenceSpecification;
import org.eclipse.uml2.uml.StateInvariant;
import org.eclipse.uml2.uml.TimeObservation;

import com.cea.papyrus.core.editor.IPropertyValue;
import com.cea.papyrus.core.editor.ModelManager;
import com.cea.papyrus.core.editpart.GraphEdgeEditPart;
import com.cea.papyrus.core.editpart.StereotypePropertiesDisplayEditPart;
import com.cea.papyrus.core.helper.ModelerHelper;
import com.cea.papyrus.core.utils.Debug;
import com.cea.papyrus.diagram.classdiagram.editpart.CommentEditPart;
import com.cea.papyrus.diagram.classdiagram.editpart.ConstraintEditPart;
import com.cea.papyrus.diagram.sequence.ISequencePropertyValue;
import com.cea.papyrus.diagram.sequence.preference.PreferenceSetter;
import com.cea.papyrus.diagram.sequence.sedi.model.util.ModelUtil;
import com.cea.papyrus.diagraminterchange2.di2.Diagram;
import com.cea.papyrus.diagraminterchange2.di2.DiagramElement;
import com.cea.papyrus.diagraminterchange2.di2.GraphEdge;
import com.cea.papyrus.diagraminterchange2.di2.GraphElement;
import com.cea.papyrus.diagraminterchange2.di2.GraphNode;
import com.cea.papyrus.diagraminterchange2.di2.SemanticModelBridge;
import com.cea.papyrus.diagraminterchange2.di2.util.Di2Switch;

/**
 * Creates EditPart instances of the right type given a model object.
 * 
 * @author Andreas Limyr
 * @author frankd@ifi.uio.no
 */
public class SeDiEditPartFactory extends Di2Switch implements EditPartFactory {

    private ModelManager modelManager;

    public SeDiEditPartFactory(ModelManager modelManager) {
        this.modelManager = modelManager;
    }

    public EditPart createEditPart(final EditPart context, final Object model) {
        if (model instanceof Diagram)
            return new DiagramEditPart((Diagram) model, modelManager);
        
        EditPart result= getEditPartFromProperty(context, model,modelManager);
		if (result!=null){
			return result;
		}
        EditPart part = (EditPart) doSwitch((EObject) model);
        if (part != null) {
            if (model instanceof GraphElement) {
                Element element = this.getElement((GraphElement) model);
                if (element != null) {
                    PreferenceSetter preferenceSetter =
                            PreferenceSetter.getPreferenceSetter(element);
                    GraphElement graphElement = (GraphElement) model;
                    if (preferenceSetter != null) {
                        preferenceSetter.setPreference(graphElement);
                    }
                    //
                    // Set stereotype presentation
                    SemanticModelBridge semanticModelBridge = graphElement.getSemanticModel();
                    semanticModelBridge.setPresentation(ModelerHelper.STEREOTYPE_TEXT_HORIZONTAL_PRESENTATION);
                }
            }
            return part;
        }

        throw new IllegalArgumentException("Can't create EditPart for: " + model);
    }

    /** This method is for internal use only. */
    @SuppressWarnings("unchecked")
    @Override
    public Object caseGraphNode(GraphNode view) {
        Element umlElement = ModelUtil.<Element> getSemantic(view);
        if (umlElement instanceof ExecutionSpecification)
            return new EOEditPart(view, modelManager);
        else if (umlElement instanceof CombinedFragment) {
            /*
             * TODO: Enable CO-regions // There is no obvious way to distinguish between a
             * PAR CF and // a co-region; we attempt the following test: // If the region
             * covers exactly 1 lifeline then it is a co-region. // otherwise it is a
             * full-size CF. CombinedFragment fragment = (CombinedFragment) umlElement; if
             * (fragment.getInteractionOperator().getValue() ==
             * InteractionOperatorKind.PAR && fragment.getCovereds().size() == 1) return
             * new CoregionEditPart(view); else
             */
            return new CFEditPart(view, modelManager);
        } else if (umlElement instanceof InteractionUse)
            return new IOEditPart(view, modelManager);
        else if (umlElement instanceof Lifeline)
            return new LifelineEditPart(view, modelManager);
        else if (umlElement instanceof Continuation)
            return new ContinuationEditPart(view, modelManager);
        else if (umlElement instanceof InteractionConstraint)
            return new GuardEditPart(view, modelManager);
        else if (umlElement instanceof StateInvariant)
            return new StateInvariantEditPart(view, modelManager);
        else if (umlElement instanceof Interaction)
            return new FrameEditPart(view, modelManager);
        if (umlElement instanceof Comment)
            return new CommentEditPart(view, modelManager);
        if (umlElement instanceof Constraint)
            return new ConstraintEditPart(view, modelManager);
        if (umlElement instanceof TimeObservation)
            return new TimeObservationEditPart(view, modelManager);
        if (umlElement instanceof DurationObservation)
            return new DurationObservationEditPart(view, modelManager);
        else if (umlElement instanceof OccurrenceSpecification) {
            Event event = ((OccurrenceSpecification) umlElement).getEvent();
            if (event instanceof DestructionEvent)
                return new TerminateEditPart(view, modelManager);
        }

        Debug.log(new Exception("Element type not managed : "+umlElement));
        return null;
    }

    /** This method is for internal use only. */
    @SuppressWarnings("unchecked")
    @Override
    public Object caseGraphEdge(GraphEdge object) {
        NamedElement umlElement = ModelUtil.<NamedElement> getSemantic(object);
        if (umlElement instanceof Message) {
            return new MessageEditPart(object, modelManager);
        } else if (umlElement instanceof InteractionOperand) {
            return new SeparatorEditPart(object, modelManager);
    	} else{
    		// This handles pseudo elements like Comment/Constraint links
			return new GraphEdgeEditPart(object,modelManager);		
		}
    }

    private Element getElement(GraphElement model) {
        return ModelUtil.<Element> getSemantic((GraphElement) model);
    }
    /**
	 * IMPORTANT: this is a new mechanism. Now use it.
	 * this method is linked to a new mechanism in papyrus to find the editpart.
	 * Each node contains a string that correspond to an editpart
	 * @param context the parent editpart
	 * @param the Diagram Element in the di2
	 * @return the good Editpart or null if it does not have an associated edipart name
	 */
	public  EditPart getEditPartFromProperty(EditPart context, Object obj, ModelManager modelManager){
		if(obj instanceof DiagramElement){
			//look for the value of editpart
			DiagramElement di2elt= (DiagramElement)obj;
			String editPartName=di2elt.getEditpartName();
			if (IPropertyValue.STEREOTYPE_PROPERTY_DISPLAY.equals(editPartName)) {
				return new StereotypePropertiesDisplayEditPart((GraphNode)obj,modelManager);
			} 
			else if(IPropertyValue.STEREOTYPE_PROPERTY_DISPLAY_EDGE.equals(editPartName)) {
				return new GraphEdgeEditPart((GraphEdge)di2elt,modelManager);	
			}
			else if (ISequencePropertyValue.SEQUENCE_DIAGRAM_DURATION_LINK.equals(editPartName)){
				return new GraphEdgeEditPart((GraphEdge)di2elt,modelManager);	
			}
			else if (ISequencePropertyValue.SEQUENCE_DIAGRAM_TIME_LINK.equals(editPartName)){
				return new GraphEdgeEditPart((GraphEdge)di2elt,modelManager);	
			}
			else{return null;}
		}
		else {return null;}
	}
    
}
